package com.bobo.mm.socket.provider;

import android.os.Handler;
import android.util.Log;

import com.bobo.mm.ClientConfig;
import com.bobo.mm.socket.InnerSocketListener;

import org.jetbrains.annotations.NotNull;

import java.lang.ref.WeakReference;

/**
 * socket客户端服务提供基类
 * Created by cocolove2 on 2020/8/11.
 */
abstract class BaseSocketClient implements ISocketClient {
    private static final String TAG = "BaseSocketClient";
    /*socket 通道连接状态*/
    final static int DISCONNECTED = -1;
    final static int CONNECTED = 0;
    final static int CONNECTING = 1;
    final static int RECONNECT = 2;
    /*socket 关闭错误码*/
    final static int CODE_NORMAL_CLOSE = 1000;
    final static int CODE_ABNORMAL_CLOSE = 1001;
    /*socket 关闭提示信息*/
    final static String TIP_NORMAL_CLOSE = "normal close";
    final static String TIP_ABNORMAL_CLOSE = "abnormal close";

    /**
     * socket会话连接状态
     */
    private int mClientConnState = DISCONNECTED;
    /**
     * 是否为手动关闭websocket连接
     */
    private boolean isManualClose = false;
    /**
     * 重连次数
     */
    private int reconCount = 0;
    /**
     * 重连时间间隔(单位ms)
     */
    private int reconDelay = 0;
    /**
     * 客户端连接配置
     */
    private ClientConfig mClientConfig;
    /**
     * socket消息回调
     */
    private InnerSocketListener mSocketListener;
    /**
     * 断开重连处理
     */
    private Handler mReConnHandler = new Handler();
    /**
     * 重新服务
     */
    private ReConnRun mReConnRun;

    public BaseSocketClient(@NotNull ClientConfig clientConfig, @NotNull InnerSocketListener listener) {
        mClientConfig = clientConfig;
        mSocketListener = listener;
    }


    @Override
    public void startConnect() {
        this.isManualClose = false;
    }

    @Override
    public void stopConnect() {
        isManualClose = true;
        stopReconHandler();
    }

    @Override
    public boolean isConnected() {
        return mClientConnState == CONNECTED;
    }

    int getClientConnState() {
        return mClientConnState;
    }

    public boolean isManualClose() {
        return isManualClose;
    }

    void setClientConnState(int clientConnState) {
        mClientConnState = clientConnState;
    }

    public void setManualClose(boolean manualClose) {
        isManualClose = manualClose;
    }

    public int getReconCount() {
        return reconCount;
    }

    public int getReconDelay() {
        return reconDelay;
    }

    ClientConfig getClientConfig() {
        return mClientConfig;
    }

    InnerSocketListener getSocketListener() {
        return mSocketListener;
    }

    /**
     * 是否正在进行重新
     *
     * @return
     */
    boolean isReconning() {
        return reconCount > 0;
    }

    /**
     * 打开重新连接处理
     */
    void startReConHandler() {
        if (!mClientConfig.isAutoReconn() || isManualClose || reconCount > 0) {
            Log.e(TAG, "未配置自动重连|正常关闭|已经正在执行重新连接，以上条件不重新开启重连尝试");
            return;
        }
        reconCount = 1;
        reconDelay = reconCount * mClientConfig.getReconnectInterval();
        mReConnRun = new ReConnRun(new WeakReference<BaseSocketClient>(this));
        mReConnHandler.postDelayed(mReConnRun, Math.min(reconDelay, mClientConfig.getReconnectMaxTime()));
    }

    /**
     * 关闭重新连接处理
     */
    void stopReconHandler() {
        if (mReConnRun != null) {
            mReConnHandler.removeCallbacks(mReConnRun);
        }
        reconCount = 0;
        reconDelay = 0;
    }


    private static class ReConnRun implements Runnable {
        private WeakReference<BaseSocketClient> context;

        ReConnRun(WeakReference<BaseSocketClient> context) {
            this.context = context;
        }

        @Override
        public void run() {
            BaseSocketClient aClient = context.get();
            //上下文为空或者socket连接状态是已连接则不继续执行后续操作
            if (aClient == null || aClient.mClientConnState == CONNECTED) return;
            Log.i(TAG, "重试连接,第" + aClient.reconCount + "次" + "#延时" + aClient.reconDelay + "ms");
            context.get().reconnect(aClient.getClientConfig().getClientId(), aClient.reconCount);
            //重试次数加1
            aClient.reconCount++;
            aClient.reconDelay = aClient.reconCount * aClient.mClientConfig.getReconnectInterval();

            if (aClient.mReConnRun != null) {
                aClient.mReConnHandler.postDelayed(aClient.mReConnRun, Math.min(aClient.reconDelay, aClient.mClientConfig.getReconnectMaxTime()));
            }
        }
    }

    abstract void reconnect(String clientId, int reconCount);

    /**
     * 失败异常，支持重试
     *
     * @param e
     */
    void failError(Exception e) {
        setClientConnState(DISCONNECTED);
        if (!isManualClose()) {
            getSocketListener().onFailure(getClientConfig().getClientId(), e, null);
        }
        //异常断开重新连接
        if (!isManualClose() && !isReconning()) {
            startReConHandler();
        }
    }
}
